#pragma once

#include <stm32f4xx.h>
#include "_mcu_gpio.h"
#include <stm32f4xx_ll_spi.h>

#include "mcu.h"

/// SPI 总线驱动数据结构
typedef struct _mcu_spi {
	/// SPI 接口控制器
	SPI_TypeDef *port;
} mcu_spi_t;


#ifdef __cplusplus
extern "C" {
#endif

/// @brief 用于定义 SPI 引脚复用关系配置函数的宏
#define _SPI_FPIN_MUX(SPIx, FPIN, PIN, AF) \
    static inline mcu_gpio_num_t SPIx##_##FPIN##_USE_##PIN() { return mcu_gpio_pinmux_config(MCU_GPIO_NUM_##PIN, LL_GPIO_AF_##AF) ? MCU_GPIO_NUM_MAX : MCU_GPIO_NUM_##PIN; }

/// @brief 定义各个 SPI 引脚复用关系配置函数
_SPI_FPIN_MUX(SPI1 , NSS , PA4 , 5);
_SPI_FPIN_MUX(SPI1 , SCK , PA5 , 5);
_SPI_FPIN_MUX(SPI1 , MISO, PA6 , 5);
_SPI_FPIN_MUX(SPI1 , MOSI, PA7 , 5);
_SPI_FPIN_MUX(SPI1 , NSS , PA15, 5);
_SPI_FPIN_MUX(SPI1 , SCK , PB3 , 5);
_SPI_FPIN_MUX(SPI1 , MISO, PA4 , 5);
_SPI_FPIN_MUX(SPI1 , MOSI, PA5 , 5);

_SPI_FPIN_MUX(SPI2 , NSS , PB9 , 5);
_SPI_FPIN_MUX(SPI2 , SCK , PB10, 5);
_SPI_FPIN_MUX(SPI2 , NSS , PB12, 5);
_SPI_FPIN_MUX(SPI2 , SCK , PB13, 5);
_SPI_FPIN_MUX(SPI2 , MISO, PB14, 5);
_SPI_FPIN_MUX(SPI2 , MOSI, PB15, 5);
_SPI_FPIN_MUX(SPI2 , MISO, PC2 , 5);
_SPI_FPIN_MUX(SPI2 , MOSI, PC3 , 5);
_SPI_FPIN_MUX(SPI2 , SCK , PD3 , 5);
_SPI_FPIN_MUX(SPI2 , NSS , PI0 , 5);
_SPI_FPIN_MUX(SPI2 , SCK , PI1 , 5);
_SPI_FPIN_MUX(SPI2 , MISO, PI2 , 5);
_SPI_FPIN_MUX(SPI2 , MOSI, PI3 , 5);
    
_SPI_FPIN_MUX(SPI3 , MOSI, PD6 , 5);
_SPI_FPIN_MUX(SPI3 , NSS , PA4 , 6);
_SPI_FPIN_MUX(SPI3 , NSS , PA15, 6);
_SPI_FPIN_MUX(SPI3 , SCK , PB3 , 6);
_SPI_FPIN_MUX(SPI3 , MISO, PB4 , 6);
_SPI_FPIN_MUX(SPI3 , MOSI, PB5 , 6);
_SPI_FPIN_MUX(SPI3 , SCK , PC10, 6);
_SPI_FPIN_MUX(SPI3 , MISO, PC11, 6);
_SPI_FPIN_MUX(SPI3 , MOSI, PC12, 6);

_SPI_FPIN_MUX(SPI4 , SCK , PE2 , 5);
_SPI_FPIN_MUX(SPI4 , NSS , PE4 , 5);
_SPI_FPIN_MUX(SPI4 , MISO, PE5 , 5);
_SPI_FPIN_MUX(SPI4 , MOSI, PE6 , 5);
_SPI_FPIN_MUX(SPI4 , NSS , PE11, 5);
_SPI_FPIN_MUX(SPI4 , SCK , PE12, 5);
_SPI_FPIN_MUX(SPI4 , MISO, PE13, 5);
_SPI_FPIN_MUX(SPI4 , MOSI, PE14, 5);

_SPI_FPIN_MUX(SPI5 , NSS , PF6 , 5);
_SPI_FPIN_MUX(SPI5 , SCK , PF7 , 5);
_SPI_FPIN_MUX(SPI5 , MISO, PF8 , 5);
_SPI_FPIN_MUX(SPI5 , MOSI, PF9 , 5);
_SPI_FPIN_MUX(SPI5 , MOSI, PF11, 5);
_SPI_FPIN_MUX(SPI5 , NSS , PH5 , 5);
_SPI_FPIN_MUX(SPI5 , SCK , PH6 , 5);
_SPI_FPIN_MUX(SPI5 , MISO, PH7 , 5);

_SPI_FPIN_MUX(SPI6 , NSS , PG8 , 5);
_SPI_FPIN_MUX(SPI6 , MISO, PG12, 5);
_SPI_FPIN_MUX(SPI6 , SCK , PG13, 5);
_SPI_FPIN_MUX(SPI6 , MOSI, PG14, 5);

/// @brief SPI 接口初始化
/// @param csn_mux_init, sck_mux_init, miso_mux_init, mosi_mux_init 配置 SPI GPIO 引脚功能复用关系 的函数指针
/// @param cpol Clock polarity when idle: LL_SPI_POLARITY_LOW / LL_SPI_POLARITY_HIGH
/// @param cpha How many clock transition is the first data capture edge: LL_SPI_PHASE_1EDGE / LL_SPI_PHASE_2EDGE
std_err_t mcu_spi_init(
	mcu_spi_t *spi,
    mcu_gpio_mux_func_init_t csn_mux_init,
    mcu_gpio_mux_func_init_t sck_mux_init,
    mcu_gpio_mux_func_init_t miso_mux_init,
    mcu_gpio_mux_func_init_t mosi_mux_init,
	uint32_t cpol,
	uint32_t cpha,
	uint32_t baudrate);

/**
 * @brief 定义 SPI 接口
 * @param SPIx SPI设备号，如 SPI1, SPI2, ..., SPI6
 * @param CSNPIN NSS/CSn 引脚号，如 PF6；如果传入 NULL，则表示由应用自已手动控制片选
 * @param SCKPIN SCK 引脚号，如 PF7
 * @param MISOPIN MISO 引脚号，如 PF8
 * @param MOSIPIN MOSI 引脚号，如 PF9
 * @param CPOL 空闲时的时钟极性(HIGH/LOW)
 * @param CPHA 时钟相位: 1EDGE=第1个时钟边沿是第1bit采样沿；2EDGE=第2个时钟边沿是第1bit采样沿
 * @param BAUDRATE
 */
#define SPI_DEFINE(NAME, SPIx, CSNPIN, SCKPIN, MISOPIN, MOSIPIN, CPOL, CPHA, BAUDRATE) \
	static mcu_spi_t  _##NAME = {.port = SPIx}; \
	mcu_spi_t*  NAME = &_##NAME; \
    const mcu_gpio_mux_func_init_t SPIx##_NSS_USE_NULL = NULL; \
	std_err_t NAME##_Init() { return mcu_spi_init(NAME, SPIx##_NSS_USE_##CSNPIN, SPIx##_SCK_USE_##SCKPIN, SPIx##_MISO_USE_##MISOPIN, SPIx##_MOSI_USE_##MOSIPIN, LL_SPI_POLARITY_##CPOL, LL_SPI_PHASE_##CPHA, BAUDRATE); }


#ifdef __cplusplus
}
#endif
